#include "VVLog.h"


VVLog::VVLog(const char *log_path, const char *log_module, VV_LOG_LEVEL level)
{
    m_log_module = log_module;
    try {
        m_logger = spdlog::rotating_logger_mt(log_module, log_path, 50 * 1024 * 1024, 2);
    }
    catch(const std::exception& e) {
        printf("open log file %s failed: %s\n", log_path, e.what());
        exit(1);
    }

    auto log_level = spdlog::level::info;
    switch(level) {
    case VV_LOG_TRACE:
        log_level = spdlog::level::trace;
        break;
    case VV_LOG_DEBUG:
        log_level = spdlog::level::debug;
        break;
    case VV_LOG_INFO:
        log_level = spdlog::level::info;
        break;
    case VV_LOG_WARN:
        log_level = spdlog::level::warn;
        break;
    case VV_LOG_ERROR:
        log_level = spdlog::level::err;
        break;
    case VV_LOG_CRITICAL:
        log_level = spdlog::level::critical;
        break;
    }

    spdlog::set_level(log_level);
    spdlog::flush_on(log_level);
    spdlog::flush_every(std::chrono::seconds(1));
}

VVLog::~VVLog()
{
    spdlog::drop(m_log_module);
    printf("vvlog shutdown\n");
    fflush(stdout);
    spdlog::shutdown();
}

void VVLog::trace(const char *fmt, va_list args)
{
    char buf[1024] = {0};
    vsnprintf(buf, sizeof(buf), fmt, args);

    m_logger->trace(buf);
}

void VVLog::debug(const char *fmt, va_list args)
{
    char buf[1024] = {0};
    vsnprintf(buf, sizeof(buf), fmt, args);

    m_logger->debug(buf);
//#if __LOG_TO_FILE
//    spdlog::apply_all([&](std::shared_ptr<spdlog::logger> l) { l->debug(buf); });
//#else
//    spdlog::debug(buf);
//#endif
}

void VVLog::info(const char *fmt, va_list args)
{
    char buf[1024] = {0};
    vsnprintf(buf, sizeof(buf), fmt, args);

    m_logger->info(buf);
}

void VVLog::warn(const char *fmt, va_list args)
{
    char buf[1024] = {0};
    vsnprintf(buf, sizeof(buf), fmt, args);

    m_logger->warn(buf);
}

void VVLog::error(const char *fmt, va_list args)
{
    char buf[1024] = {0};
    vsnprintf(buf, sizeof(buf), fmt, args);

    m_logger->error(buf);
}

void VVLog::critical(const char *fmt, va_list args)
{
    char buf[1024] = {0};
    vsnprintf(buf, sizeof(buf), fmt, args);

    m_logger->critical(buf);
}

void VVLog::trace_s(const char *buf)
{
    m_logger->trace(buf);
}

void VVLog::debug_s(const char *buf)
{
    m_logger->debug(buf);
}

void VVLog::info_s(const char *buf)
{
    m_logger->info(buf);
}

void VVLog::warn_s(const char *buf)
{
    m_logger->warn(buf);
}

void VVLog::error_s(const char *buf)
{
    m_logger->error(buf);
}

void VVLog::critical_s(const char *buf)
{
    m_logger->critical(buf);
}

#if 0
#include <mutex>

#include "spdlog/spdlog.h"
#include "spdlog/sinks/basic_file_sink.h"
#include "spdlog/sinks/daily_file_sink.h"
#include "spdlog/sinks/rotating_file_sink.h"
#include "spdlog/sinks/stdout_sinks.h"

#include "vv_log.h"

#define __LOG_MODULE_NAME ""
#define __LOG_TO_FILE 1

#ifdef linux
#define APP_MODE_LOG_FILE_PATH "/var/log/v2v_drv.log" /*user must have the right to write the folder*/
#else
#define APP_MODE_LOG_FILE_PATH "vv.log"
#endif


static int s_is_vv_log_inited=0;
static VV_LOG_LEVEL s_log_level = VV_LOG_INFO;

void vv_log_init()
{
    if(s_is_vv_log_inited != 0)
        return ;

    static std::mutex s_init_lock;
    std::lock_guard<std::mutex> lock(s_init_lock);

#if __LOG_TO_FILE
    // There is a default logger existed at the beginning which will only write to console, so we drop all logger first here to create a logger writing into file only
    spdlog::drop_all();

    try {
        auto vvdektop_logger = spdlog::rotating_logger_mt(__LOG_MODULE_NAME, APP_MODE_LOG_FILE_PATH, 50 * 1024 * 1024, 2);
    }
    catch(...) {
        printf("open log file \"vv.log\" failed, please give writing previledge to the app.\n");

#ifndef linux
        MessageBoxA(NULL, "open log file \"vv.log\" failed, please give writing previledge to the app.\n", "tips", MB_OK);
#endif
        return;
    }
#endif

    auto level = spdlog::level::info;
    switch(s_log_level) {
    case VV_LOG_TRACE:
        level = spdlog::level::trace;
        break;
    case VV_LOG_DEBUG:
        level = spdlog::level::debug;
        break;
    case VV_LOG_INFO:
        level = spdlog::level::info;
        break;
    case VV_LOG_WARN:
        level = spdlog::level::warn;
        break;
    case VV_LOG_ERROR:
        level = spdlog::level::err;
        break;
    case VV_LOG_CRITICAL:
        level = spdlog::level::critical;
        break;
    }

    //If you want debug message to be displayed, this sentence is needed
    spdlog::set_level(level);

#if __LOG_TO_FILE
    spdlog::flush_on(level);
    // Flush all *registered* loggers using a worker thread every 3 seconds.
    // note: registered loggers *must* be thread safe for this to work correctly!
    spdlog::flush_every(std::chrono::seconds(1));
#endif

    s_is_vv_log_inited = 1;
}

void vv_debug(const char *fmt, ...);
void vv_info(const char *fmt, ...);
void vv_warn(const char *fmt, ...);
void vv_error(const char *fmt, ...);

void vv_debug_fun(const char *fmt, ...)
{
    vv_log_init();

    va_list b;
    va_start(b, fmt);

    char buf[1024];
    memset(buf,0,sizeof(buf));

    vsnprintf(buf, sizeof(buf), fmt, b);
    buf[1023] = 0;

#if __LOG_TO_FILE
    spdlog::apply_all([&](std::shared_ptr<spdlog::logger> l) { l->debug(buf); });
#else
    spdlog::debug(buf);
#endif

    va_end(b);
}

void vv_info_fun(const char *fmt, ...)
{
    vv_log_init();

    va_list b;
    va_start(b, fmt);

    char buf[1024];
    vsnprintf(buf, sizeof(buf), fmt, b);
    buf[1023] = 0;

#if __LOG_TO_FILE
    spdlog::apply_all([&](std::shared_ptr<spdlog::logger> l) { l->info(buf); });
#else
    spdlog::info(buf);
#endif

    va_end(b);
}

void vv_warn_fun(const char *fmt, ...)
{
    vv_log_init();

    va_list b;
    va_start(b, fmt);

    char buf[1024];
    vsnprintf(buf, sizeof(buf), fmt, b);
    buf[1023] = 0;

#if __LOG_TO_FILE
    spdlog::apply_all([&](std::shared_ptr<spdlog::logger> l) { l->warn(buf); });
#else
    spdlog::warn(buf);
#endif

    va_end(b);
}

void vv_error_fun(const char *fmt, ...)
{
    vv_log_init();

    va_list b;
    va_start(b, fmt);

    char buf[1024];
    vsnprintf(buf, sizeof(buf), fmt, b);
    buf[1023] = 0;

#if __LOG_TO_FILE
    spdlog::apply_all([&](std::shared_ptr<spdlog::logger> l) { l->error(buf); });
#else
    spdlog::error(buf);
#endif

    va_end(b);
}

void vv_log_destroy()
{
    if (s_is_vv_log_inited == 0)
        return;

    static std::mutex s_destory_lock;
    std::lock_guard<std::mutex> lock(s_destory_lock);

#if __LOG_TO_FILE
    spdlog::shutdown();
#endif

    s_is_vv_log_inited = 0;
}


static class __bm {public: __bm(){
    //doing vv_log_init() here works ok in app, but failed in dll, because can't create thread in that time.
};~__bm(){
    //vv_log_destroy(); // do not destory it here, because some global variables that spdlog depends one already released.
};}__bm0;

void vv_log_set_level(VV_LOG_LEVEL level)
{
    s_log_level = level;
}

#endif
